﻿using Function_Analyzer.MathUtil;
using Function_Analyzer.Objects;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using ThreadPool;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.System.Threading;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace Function_Analyzer
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class KhaosatPage : Page
    {
        string hs = "x^4-x^3+x+1";

        string dh, dh2;
        double cdau, ccuoi;
        List<double> xmax;
        List<double> xmin;
        double ymax, ymin;
        List<double> dsct;
        List<double> dsdu;
        int slmax, slmin, slct, sldu, sldbnb;

        //reault
        List<Diembatdinh> dsdbd;
        List<Diemxetdongbiennghichbien> dsddbnb;
        List<double> dsn;

        public KhaosatPage()
        {
            this.InitializeComponent();
            

            ThreadPoolSample.WorkItemScenaioro = this;
            ThreadPoolSample.WorkItemPriority = WorkItemPriority.High;
            //test();
            CreateThreadPoolWorkItem();
        }

        private void test()
        {
            Debug.WriteLine(Util.ReplaceVar(hs,'x',"-0.12345456"));
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            hs = e.Parameter.ToString();
            Debug.WriteLine(hs);
            UpdateUI(ThreadPoolSample.WorkItemStatus);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
        }

        private void CreateThreadPoolWorkItem()
        {
            ThreadPoolSample.ThreadPoolWorkItem = Windows.System.Threading.ThreadPool.RunAsync(
                (source) =>
                {
                    //if (source.Status == AsyncStatus.Canceled)
                    //{
                    //    break;
                    //}

                    //update UI
                    var vartbFunc = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbFunc.Text = "y = " + hs;
                    });

                    KhoiPhucSo kps=new KhoiPhucSo();
                    double ytb;
            

                    cdau = -255;
                    ccuoi = 255;

                    hs = DaoHam.EditedEqu(hs);
                    Taodsdiem();

                    //1. tap xac dinh
                    var var1 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbTientrinh.Text = "Tìm các điểm gián đoạn và tập xác định...";
                        proTientrinh.Value = 80;
                    });
                    string rs1 = "D = ";

                    string[] dau = new string[2];
                    string[] can = new string[2];
                    MathCal.Init(hs, 0);

                    //add them can dau can cuoi
                    Diembatdinh dd = new Diembatdinh();
                    dd.x = cdau;
                    dd.loai = 0;
                    dsdbd.Insert(0,dd);
                    dd = new Diembatdinh();
                    dd.x = ccuoi;
                    dd.loai = 0;
                    dsdbd.Add(dd);

                    Debug.WriteLine("dsdbd.Count" + dsdbd.Count);


                    for (int i = 0; i < dsdbd.Count-1; i++)
                    {
                        ytb = MathCal.GetVal((dsdbd[i].x + dsdbd[i + 1].x) / 2, 0);
                        if (!MathCal.error)
                        {
                            if (!Util.IsNumericStr(KhaoSat.Tim_gh(hs, dsdbd[i].x.ToString()).gh) || dsdbd[i].loai == 1 || dsdbd[i].loai == 2 || dsdbd[i].x == -255)
                            {
                                dau[0] = "(";
                            }
                            else dau[0] = "[";

                            if (!Util.IsNumericStr(KhaoSat.Tim_gh(hs, dsdbd[i+1].x.ToString()).gh) || dsdbd[i+1].loai == 1 || dsdbd[i+1].loai == 2 || dsdbd[i+1].x == 255)
                            {
                                dau[1] = "(";
                            }
                            else dau[1] = "[";

                            can[0] = (dsdbd[i].x == -255 ? "-∞" : dsdbd[i].x.ToString());
                            can[1] = (dsdbd[i+1].x == 255 ? "+∞" : dsdbd[i+1].x.ToString());

                            rs1 += dau[0] + kps.FixVal(can[0]) + " ; " + kps.FixVal(can[1]) + dau[1] + (i < dsdbd.Count ? " U " : "");
                        }
                    }
                    dsdbd.RemoveAt(dsdbd.Count - 1);
                    Debug.WriteLine(rs1);

                    //update UI
                    var vartbResult1 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbResult1.Text = rs1;
                        tbResult1.Visibility = Windows.UI.Xaml.Visibility.Visible;
                    });

                    


                    //2. bien thien
                    //trc bang bien thien
                    string rs2a = "";
                    //tinh dao ham, giai y'=0
                    rs2a += "a) Đạo hàm\n"+"    y' = "+dh+"\n    y' = 0 ↔ ";
                    MathCal.Init(hs, 0);
                    if (dsct.Count == 0)
                    {
                        rs2a += "Vô nghiệm, hàm số không có cực trị";
                    }
                    else
                    {
                        for (int i = 0; i < dsct.Count; i++)
                        {
                            rs2a += "x = " + kps.FixVal(dsct[i]) + " ; ";
                        }
                        rs2a += "        ↔ Hàm số đạt " + dsct.Count + " cực trị tại: ";
                        for (int i = 0; i < dsct.Count; i++)
                        {
                            rs2a += "A ( " + kps.FixVal(dsct[i]) + " ; "+kps.FixVal(MathCal.StrGetVal(dsct[i],0))+" ), ";
                        }
                    }

                    //update UI
                    var vartbResult2a = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbResult2a.Text = rs2a;
                        tbResult2a.Visibility = Windows.UI.Xaml.Visibility.Visible;
                        tbTientrinh.Text = "Tìm các tiệm cận...";
                    });

                    //xet gioi han va tiem can
                    rs2a += "\nb) Giới hạn và các đường tiệm cận\n";
                    bool cotcd = false;
                    bool cotcn = false;
                    bool cotcx = false;
                    //tiem can dung
                    for (int i = 1; i < dsdbd.Count; i++)
                    {
                        rs2a += "    + Ta có\n";
                        rs2a += "        lim y (x→" + kps.FixVal(dsdbd[i].x) + "-) = " + kps.FixVal(KhaoSat.Tim_gh(hs, dsdbd[i].x.ToString()).gham) + "\n";
                        rs2a += "        lim y (x→" + kps.FixVal(dsdbd[i].x) + "+) = " + kps.FixVal(KhaoSat.Tim_gh(hs, dsdbd[i].x.ToString()).ghduong) + "\n";
                        rs2a += "        → đường thẳng x = " + kps.FixVal(dsdbd[i].x) + " là tiệm cận đứng của đồ thị hàm số đã cho\n";
                        cotcd = true;
                    }

                    //tiem can ngang
                    string gh1=KhaoSat.Tim_gh(hs, "++").gh;
                    string gh2=KhaoSat.Tim_gh(hs, "--").gh;
                    rs2a += "    Giới hạn tại vô cực\n";
                    rs2a += "        lim y (x→ +∞) = " + kps.FixVal(gh1) + "\n";
                    rs2a += "        lim y (x→ -∞) = " + kps.FixVal(gh2) + "\n";
                    if (gh1 == gh2 && !gh1.Contains("∞") && gh1 != "#")
                    {
                        rs2a += "        → đường thẳng y = " + gh1 + " là đường tiệm cận ngang của đồ thị hàm số đã cho\n";
                        cotcn = true;
                    }

                    //tiem can xien
                    string ghxa = KhaoSat.Tim_gh("("+hs+")/x", "++").gh;
                    string tcx = "";
                    if (MathCal.Val(ghxa) != 0)
                    {
                        string ghxb = KhaoSat.Tim_gh(hs +"-"+ghxa+"*x", "++").gh;
                        if (!ghxb.Contains("∞"))
                        {
                            if (Convert.ToDouble(ghxb) == 0)
                            {
                                tcx = ghxa + "x";
                            }
                            else tcx = ghxa + "x" + (MathCal.Val(ghxb) < 0 ? MathCal.Val(ghxb).ToString() : "+" + MathCal.Val(ghxb));
                            //if()

                            //phan get limit bo qua
                        }
                    }

                    //update UI
                    var vartbResult2a1 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbResult2a.Text = rs2a;
                        tbTientrinh.Text = "Vẽ bảng biến thiên...";
                        proTientrinh.Value = 90;
                        
                    });
                    
                    //sau bang bien thien
                    string rs2b = "";

                    //update UI
                    var vartbResult2a2 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbTientrinh.Text = "Xét đồng biến, nghịch biến...";
                    });
                    //xet dong bien ngich bien
                    rs2b += "d) Chiều biến thiên và cực trị\n";
                    MathCal.Init(hs, 0);
                    MathCal.Init(dh, 1);
                    double x1 = cdau;
                    for (int i = 0; i < dsddbnb.Count; i++)
                    {
                        if (dsddbnb[i].loai == 0 || dsddbnb[i].loai == 2 || dsddbnb[i].loai == 3)
                        {
                            double x2 = dsddbnb[i].x;
                            if (MathCal.StrGetVal(x2 - 0.01, 1) == "Error" || MathCal.StrGetVal(x2 - 0.01, 0) == "Error")
                            {
                                x1 = x2;
                                continue;
                            }
                            double ydh=MathCal.GetVal(x2-0.01,1);
                            if(ydh>0){
                                rs2b+="    + Hàm số đồng biến trên ( " + (x1==-255?"-∞":kps.FixVal(x1)) + " ; "+(x2==255?"+∞":kps.FixVal(x1))+")\n";
                            }
                            if(ydh<0){
                                rs2b+="    + Hàm số nghịch biến trên ( " + (x1==-255?"-∞":kps.FixVal(x1)) + " ; "+(x2==255?"+∞":kps.FixVal(x1))+")\n";
                            }
                            x1=x2;
                        }
                    }

                    //xet cuc tri va max, min
                    slmax = 0;
                    slmin = 0;
                    ymax = Double.MinValue;
                    ymin = Double.MaxValue;
                    MathCal.Init(hs, 0);
                    MathCal.Init(dh2, 2);
                    for (int i = 0; i < dsct.Count; i++)
                    {
                        GetMaxMin(dsct[i], MathCal.GetVal(dsct[i], 0), (MathCal.GetVal(dsct[i], 2) < 0 ? "CD" : "CT"));
                    }
                    if (ymax != Double.MinValue)
                    {
                        rs2b += "    + Hàm số đạt cực đại tại điểm ";
                        for (int i = 0; i < slmax; i++)
                        {
                            rs2b += "x = " + kps.FixVal(xmax[i]) + "; ";
                        }
                        rs2b += "giá trị cực đại của hàm số là y = " + kps.FixVal(ymax) + "\n";
                    }
                    if (ymin != Double.MaxValue)
                    {
                        rs2b += "    + Hàm số đạt cực tiểu tại điểm ";
                        for (int i = 0; i < slmax; i++)
                        {
                            rs2b += "x = " + kps.FixVal(xmax[i]) + "; ";
                        }
                        rs2b += "giá trị cực tiểu của hàm số là y = " + kps.FixVal(ymin) + "\n";
                    }

                    //update UI
                    var vartbResult2b = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbResult2b.Text = rs2b;
                        tbResult2b.Visibility = Windows.UI.Xaml.Visibility.Visible;
                    });

                    //ve do thi
                    string rs3 = "";
                    rs3 += "a) Giao điểm của đồ thị với các trục tọa độ\n";
                    rs3 += "    + Giao điểm của hàm số với trục Ox\n";
                    rs3 += "        y = 0 ↔ ";
                    dsn=KhaoSat.Tim_ng(hs, cdau, ccuoi, "", true);
                    MathCal.Init(hs, 0);
                    if (dsn.Count == 0)
                    {
                        rs3 += "Vô nghiệm, hàm số không cắt trục Ox\n";
                    }
                    else
                    {
                        for (int i = 0; i < dsn.Count; i++)
                        {
                            rs3 += "x = " + kps.FixVal(dsn[i]) + " ; ";
                        }
                    }
                    rs3 += "\n    + Giao điểm của hàm số với trục Oy\n";
                    rs3 += "        x = 0 ↔ y = " + kps.FixVal(MathCal.StrGetVal(0, 0)) + "\n";




                    //update UI
                    var vartbResult3 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbResult3.Text = rs3;
                        tbResult3.Visibility = Windows.UI.Xaml.Visibility.Visible;
                    });
                    

                    var varFinish = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        tbTientrinh.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                        proTientrinh.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                    });
                },
            ThreadPoolSample.WorkItemPriority);

            // Register a completed-event handler to run when the work item finishes or is canceled.

            ThreadPoolSample.ThreadPoolWorkItem.Completed = new AsyncActionCompletedHandler(
                async (IAsyncAction source, AsyncStatus status) =>
                {
                    await Dispatcher.RunAsync(
                        CoreDispatcherPriority.High,
                        () =>
                        {
                            switch (status)
                            {
                                case AsyncStatus.Started:
                                    ThreadPoolSample.WorkItemScenaioro.UpdateUI(Status.Started);
                                    break;
                                case AsyncStatus.Completed:
                                    ThreadPoolSample.WorkItemScenaioro.UpdateUI(Status.Completed);
                                    break;
                                case AsyncStatus.Canceled:
                                    ThreadPoolSample.WorkItemScenaioro.UpdateUI(Status.Canceled);
                                    break;
                            }
                        });
                });

            UpdateUI(Status.Started);
        }

        private void CancelThreadPoolWorkItem(object sender, RoutedEventArgs args)
        {
            if (ThreadPoolSample.ThreadPoolWorkItem != null)
            {
                ThreadPoolSample.ThreadPoolWorkItem.Cancel();
            }
        }

        public void UpdateUI(Status status)
        {
            ThreadPoolSample.WorkItemStatus = status;

            //tbResult3.Text = status.ToString("g");
            //WorkItemInfo.Text = string.Format("Work item priority = {0}", ThreadPoolSample.WorkItemPriority.ToString("g"));

            var createButtonEnabled = (status != Status.Started);
            //CreateThreadPoolWorkItemButton.IsEnabled = createButtonEnabled;
            //CancelThreadPoolWorkItemButton.IsEnabled = !createButtonEnabled;
        }

        public void UpdateWorkItemProgressUI(long percentComplete)
        {
            //tbResult3.Text = string.Format("Progress: {0}%", percentComplete.ToString());
        }

        private void Taodsdiem()
        {
            dsdbd = new List<Diembatdinh>();
            dsct = new List<double>();
            dsddbnb = new List<Diemxetdongbiennghichbien>();
            slct = 0;
            sldbnb = 0;

            //bat dinh
            var var1 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
            {
                tbTientrinh.Text = "Khởi tạo và tính toán số liệu ban đầu...";
            });
            dsdbd=KhaoSat.Tim_bd(hs, cdau, ccuoi, tbTientrinh, proTientrinh, Dispatcher);

            for (int i = 0; i < dsdbd.Count; i++)
            {
                Diemxetdongbiennghichbien d = new Diemxetdongbiennghichbien();
                d.x = dsdbd[i].x;
                d.loai = 2;
                dsddbnb.Add(d);
            }

            //cuc tri
            var var2 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
            {
                tbTientrinh.Text = "Tìm đạo hàm và xác định các cực trị...";
                proTientrinh.Value = 70;
            });

            dh = DaoHam.GetDerivative(hs);
            dsn = KhaoSat.Tim_ng(dh, cdau, ccuoi, "", true);
            MathCal.Init(hs, 0);
            MathCal.Init(dh, 1);
            for (int i = 0; i < dsn.Count; i++)
            {
                string y1 = MathCal.StrGetVal(dsn[i] - 0.01, 0);
                string y2 = MathCal.StrGetVal(dsn[i] + 0.01, 0);
                if (y1 != "Error" && y2 != "Error")
                {
                    string ydh1 = MathCal.StrGetVal(dsn[i] - 0.01, 1);
                    string ydh2 = MathCal.StrGetVal(dsn[i] + 0.01, 1);
                    if (Convert.ToDouble(ydh1) * Convert.ToDouble(ydh2) < 0)
                    {
                        dsct.Add(dsn[i]);
                        Diemxetdongbiennghichbien d = new Diemxetdongbiennghichbien();
                        d.x = dsn[i];
                        d.loai = 0;
                        dsddbnb.Add(d);
                    }
                }
            }

            //diem uon
            var var3 = Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
            {
                tbTientrinh.Text = "Xác định vị trí các điểm uốn...";
                proTientrinh.Value = 75;
            });
            dsdu = new List<double>();
            dh2 = DaoHam.GetDerivative(dh);
            dsn = KhaoSat.Tim_ng(dh2, cdau, ccuoi, "", false);
            MathCal.Init(hs, 0);
            MathCal.Init(DaoHam.EditedEqu(dh2), 2);
            for (int i = 0; i < dsn.Count; i++)
            {
                string ydh1 = MathCal.StrGetVal(dsn[i] - 0.01, 2);
                string ydh2 = MathCal.StrGetVal(dsn[i] + 0.01, 2);
                if (Convert.ToDouble(ydh1) * Convert.ToDouble(ydh2) < 0)
                {
                    dsdu.Add(dsn[i]);
                }
            }

            //sap xep
            Diemxetdongbiennghichbien tam;
            for (int i = 0; i < dsddbnb.Count; i++)
                for(int j=0;j<dsddbnb.Count;j++)
                    if (dsddbnb[j].x < dsddbnb[i].x)
                    {
                        tam = dsddbnb[i];
                        dsddbnb[i] = dsddbnb[j];
                        dsddbnb[j] = tam;
                    }
            
            //them can dau, cuoi
            Diemxetdongbiennghichbien dd = new Diemxetdongbiennghichbien();
            dd.x = ccuoi;
            dd.loai = 2;
            dsddbnb.Add(dd);
        }

        private void GetMaxMin(double x, double y, string loai)
        {
            if (Math.Round(y, 6) > Math.Round(ymax, 6) && loai == "CD")
            {
                ymax = y;
                xmax = new List<double>();
                xmax.Add(x);
            }
            else if (Math.Round(y, 6) == Math.Round(ymax, 6) && loai == "CD")
            {
                xmax.Add(x);
            }
            if (Math.Round(y, 6) < Math.Round(ymin, 6) && loai == "CT")
            {
                ymin = y;
                xmin = new List<double>();
                xmin.Add(x);
            }
            else if (Math.Round(y, 6) == Math.Round(ymin, 6) && loai == "CT")
            {
                xmin.Add(x);
            }
        }
    }
}
